var Settings = regSettings('chatServer',{
	// Port to run the server on
	port: 8101,
	// Prefix for guest accounts
	guest_prefix: 'Guest_',
	// File that contains the motd
	Motd: 'data/motd.txt',
	// How quickly to check if the port is in use
	check_interval: 1000,
	// how many times to check before failing to start
	check_timeout: 10
});
if(!fs.exists(Settings.Motd)){
	fs.writeFile(Settings.Motd,"stub",function(err) {
		if(err) {
			disp.error(err);
		}else{
			disp.log("No Motd file exists, stub created");
		}
	});
}
var chat, io,
	users = global.users = listdb.getDB('users'),
	count = 0,
	chat = http.createServer(function(req, res){
		disp.log((new Date())+' Received request for '+req.url);
		if(typeof config.logServer != 'undefined'){
			res.writeHead('307',{
				'Location':"http://"+(new RegExp("(?:http.*://)?([^:/ ]+).?([0-9]*).*")).exec(req.headers.host)[1]+':'+config.logServer.port+req.url
			});
		}else{
			res.writeHead('404');
		}
		res.end();
	}),
	io = global.io = require('socket.io').listen(chat);
	chat.listen(Settings.port,function(){
		disp.log((new Date()) + ' Server is listening on port '+Settings.port);
	});
chat.on('error',function(e){
	if(e.code == 'EADDRINUSE'){
		setTimeout(function(){
			if(count < Settings.check_timeout){
				count++;
				disp.log("Port "+Settings.port+" in use, reconnect attempt: "+count);
				try{
					chat.close();
				}catch(e){}
				chat.listen(Settings.port);
			}else{
				count = 0;
				disp.log('Port in use, stopping');
			}
		},Settings.check_interval);
	}
});
io.set('log level',1);
io.sockets.on('connection',function(socket){
	socket.emit('register');
	socket.on('register', function(data){
		for(var i in data){
			if(i=='nick'){
				if(data[i] !== null){
					data[i] = data[i].substring(0,10);
					if(data[i].trim()==='' || inArray(data[i],userlist()) || data[i] === 'Server'){
						data[i] = Settings.guest_prefix+(Math.ceil(Math.random()*10000)+999);
					}
				}else{
					data[i] = Settings.guest_prefix+(Math.ceil(Math.random()*10000)+999);
				}
			}
			if(i!='op'){
				socket.set(i,data[i]);
			}
			socket.set('op','false');
		}
		socket.set('ip',socket.handshake.address.address);
		socket.get('nick',function(err,nick){
		socket.broadcast.emit('user-connect',htmlEntities(nick));
			console.log("* "+htmlEntities(nick)+" connected");
			//broadcast('user-list',userlist());
			socket.get('username',function(e,username){
				if(!e&&username){
					socket.get('password',function(e,password){
						if(!e&&password){
							if(users.hasValue(JSON.stringify({username:username,password:password}))){
								socket.set('op','true');
								//broadcast('user-list',userlist());
								broadcast('user-chat',"* "+nick+" was opped");
							}
						}
					});
				}
			});
		});
	});
});
hook('unload',function(){
	try{
		io.server.close();
		disp.alert("Chat Server Ended");
		htmlEntities = null;
		broadcast = null;
	}catch(e){
		disp.log(e.trace);
		disp.log(e);
		disp.alert("Chat Server Already Ended");
	}
});
function htmlEntities(str){
	return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
function broadcast(event,data){
	if(event=='user-chat'){
		io.sockets.emit(event,htmlEntities(data));
		console.log(data);
	}else{
		io.sockets.emit(event,data);
	}
}
var userlist = global.userlist = function(filter){
	var usersls = [];
	for(var i in io.sockets.sockets){
		if(i&&io.sockets.sockets[i]!=undefined){
			io.sockets.sockets[i].get('nick',function(err,nick){
				if(!err&&nick!=filter){
					io.sockets.sockets[i].get('op',function(err,op){
						if(op=='true'&&!err){
							usersls.push("@"+htmlEntities(nick));
						}else{
							usersls.push(htmlEntities(nick));
						}
					});
				}
			});
		}
	}
	for(var i in usersls){
		if(!usersls[i]){
			usersls.splice(i,1);
		}
	}
	return usersls;
}
/*
    Old Server
*/
function oldServer(){
	io.sockets.on('connection', function(socket){
		socket.emit('register');
		socket.on('register', function(data){
			for(var i in data){
				if(i=='nick'){
					if(data[i] != null){
						data[i] = data[i].substring(0,10);
						if(data[i].trim()=='' || inArray(data[i],userlist()) || data[i] == 'Server'){
							data[i] = Settings.guest_prefix+(Math.ceil(Math.random()*10000)+999);
						}
					}else{
						data[i] = Settings.guest_prefix+(Math.ceil(Math.random()*10000)+999);
					}
				}
				if(i!='op'){
					socket.set(i,data[i]);
				}
				socket.set('op','false');
			}
			socket.set('ip',socket.handshake.address.address);
			socket.get('nick',function(err,nick){
				socket.broadcast.emit('user-connect',htmlEntities(nick));
				console.log("* "+htmlEntities(nick)+" connected");
				socket.emit('user-list',userlist());
				socket.broadcast.emit('user-list',userlist());
				socket.get('username',function(e,username){
					if(!e&&username){
						socket.get('password',function(e,password){
							if(!e&&password){
								if(users.hasValue(JSON.stringify({username:username,password:password}))){
									socket.set('op','true');
									broadcast('user-list',userlist());
									broadcast('user-chat',"* "+nick+" was opped");
								}
							}
						});
					}
				});
			});
		});
		socket.on('user-list',function(){
			socket.emit('user-list',userlist());
		});
		socket.on('user-op',function(user){
			user = user.trim();
			socket.get('op',function(e,o){
				if(!e&&o=='true'){
					if(inArray(user,userlist())){
						for(var i in io.sockets.sockets){
							if(i&&io.sockets.sockets[i]!=undefined){
								io.sockets.sockets[i].get('nick',function(err,nick){
									if(!err&&nick==user){
										io.sockets.sockets[i].set('op','true');
										broadcast('user-list',userlist());
										broadcast('user-chat',"* "+nick+" was opped");
									}
								});
							}
						}
					}else{
						socket.emit('user-chat',htmlEntities("* User "+user+" does not exist or already opped"));
					}
				}else{
					socket.emit('user-chat',htmlEntities("* Insufficient rights"));
				}
			});
		});
		socket.on('user-whois',function(user){
			user = user.trim();
			if(inArray(user,userlist())||inArray('@'+user,userlist())){
				for(var i in io.sockets.sockets){
					if(i&&io.sockets.sockets[i]!=undefined){
						io.sockets.sockets[i].get('nick',function(err,nick){
							if(!err&&nick==user){
								io.sockets.sockets[i].get('username',function(err,username){
									socket.emit('user-chat',"* == Start Whois ==");
									socket.emit('user-chat',"* Nick: "+nick);
									if(!err&&username){
										socket.emit('user-chat',"* Username: "+username);
									}else{
										socket.emit('user-chat',"* Username:");
									}
									io.sockets.sockets[i].get('ip',function(err,ip){
										if(!err&&ip){
											socket.emit('user-chat',"* ip: "+ip);
										}else{
											socket.emit('user-chat',"* ip:");
										}
										socket.emit('user-chat',"* == End Whois ==");
									});
								});
							}else{
								socket.emit('user-chat',htmlEntities("* Error trying to whois "+user));
							}
						});
					}
				}
			}else{
				socket.emit('user-chat',htmlEntities("* User "+user+" does not exist"));
			}
		});
		socket.on('user-add',function(user){
			user = user.trim();
			socket.get('op',function(e,o){
				if(!e&&o=='true'){
					if(inArray(user,userlist())){
						for(var i in io.sockets.sockets){
							if(i&&io.sockets.sockets[i]!=undefined){
								io.sockets.sockets[i].get('nick',function(err,nick){
									if(!err&&nick==user){
										io.sockets.sockets[i].set('op','true');
										broadcast('user-list',userlist());
										broadcast('user-chat',"* "+nick+" was opped");
										io.sockets.sockets[i].get('username',function(e,username){
											if(!e&&username){
												io.sockets.sockets[i].get('password',function(e,password){
													if(!e&&password){
														if(!users.hasValue(JSON.stringify({username:username,password:password}))){
															socket.emit("* "+nick+" added to opers list");
															users.add(JSON.stringify({username:username,password:password}));
														}
													}
												});
											}
										});
									}
								});
							}
						}
					}else{
						socket.emit('user-chat',htmlEntities("* User "+user+" does not exist or already opped"));
					}
				}else{
					socket.emit('user-chat',htmlEntities("* Insufficient rights"));
				}
			});
		});
		socket.on('user-remove',function(user){
			user = user.trim();
			socket.get('op',function(e,o){
				if(!e&&o=='true'){
					if(inArray(user,userlist())||inArray('@'+user,userlist())){
						for(var i in io.sockets.sockets){
							if(i&&io.sockets.sockets[i]!=undefined){
								io.sockets.sockets[i].get('nick',function(err,nick){
									if(!err&&nick==user){
										io.sockets.sockets[i].set('op','false');
										broadcast('user-list',userlist());
										broadcast('user-chat',"* "+nick+" was deopped");
										io.sockets.sockets[i].get('username',function(e,username){
											if(!e&&username){
												io.sockets.sockets[i].get('password',function(e,password){
													if(!e&&password){
														if(users.hasValue(JSON.stringify({username:username,password:password}))){
															socket.emit("* "+nick+" removed from opers list");
															users.remove(JSON.stringify({username:username,password:password}));
														}
													}
												});
											}
										});
									}
								});
							}
						}
					}else{
						socket.emit('user-chat',htmlEntities("* User "+user+" does not exist or already opped"));
					}
				}else{
					socket.emit('user-chat',htmlEntities("* Insufficient rights"));
				}
			});
		});
		socket.on('user-deop',function(user){
			user = user.trim();
			socket.get('op',function(e,o){
				if(!e&&o=='true'){
					if(inArray("@"+user,userlist())){
						for(var i in io.sockets.sockets){
							if(i&&io.sockets.sockets[i]!=undefined){
								io.sockets.sockets[i].get('nick',function(err,nick){
									if(!err&&nick==user){
										io.sockets.sockets[i].set('op','false');
										broadcast('user-list',userlist());
										broadcast('user-chat',"* "+nick+" was deopped");
									}
								});
							}
						}
					}else{
						socket.emit('user-chat',htmlEntities("* User "+user+" does not exist or not opped"));
					}
				}else{
					socket.emit('user-chat',htmlEntities("* Insufficient rights"));
				}
			});
		});
		socket.on('user-selfop',function(){
			socket.get('nick',function(err,nick){
				socket.broadcast.emit('user-connect',htmlEntities(nick));
				socket.emit('user-list',userlist());
				socket.broadcast.emit('user-list',userlist());
				socket.get('username',function(e,username){
					if(!e&&username){
						socket.get('password',function(e,password){
							if(!e&&password){
								if(users.hasValue(JSON.stringify({username:username,password:password}))){
									socket.set('op','true');
									broadcast('user-list',userlist());
									broadcast('user-chat',"* "+nick+" was opped");
								}
							}
						});
					}
				});
			});
		});
		socket.on('user-kick',function(user){
			user = user.trim();
			socket.get('op',function(e,o){
				if(!e&&o=='true'){
					if(inArray(user,userlist())){
						for(var i in io.sockets.sockets){
							if(i&&io.sockets.sockets[i]!=undefined){
								io.sockets.sockets[i].get('nick',function(err,nick){
									if(!err&&nick==user){
										broadcast('user-chat',"* "+nick+" was kicked");
										io.sockets.sockets[i] = undefined;
										broadcast('user-list',userlist());
									}
								});
							}
						}
					}else{
						socket.emit('user-chat',htmlEntities("* User does not exist"));
					}
				}else{
					socket.emit('user-chat',htmlEntities("* Insufficient rights"));
				}
			});
		});
		socket.on('motd',function(){
			socket.emit('motd',fs.readFileSync(Settings.Motd,'utf-8'));
		});
		socket.on('disconnect',function(){
			socket.get('nick',function(err,nick){
				socket.broadcast.emit('user-quit',htmlEntities(nick));
				socket.broadcast.emit('user-list',userlist(nick));
			});
		});
		socket.on('user-chat',function(msg){
			if(msg.trim()!=''){
				socket.get('nick',function(err,nick){
					broadcast('user-chat',"< "+nick+" >	"+msg);
				});
			}
		});
		socket.on('user-action',function(msg){
			if(msg.trim()!=''){
				socket.get('nick',function(err,nick){
					broadcast('user-chat',"* "+nick+" "+msg);
				});
			}
		});
		socket.on('user-clear',function(){
			socket.emit('clear');
			socket.emit('user-list',userlist());
		});
		socket.on('user-kick',function(user){
			socket.get('op',function(err,op){
				if(op&&!err){
					socket.broadcast.emit('user-chat','* '+user+' was kicked from the server');
				}else{
					socket.send('user-chat','* You are not an op *');
				}
			});
		});
	});
	// Setup Input Console
	function inputConsole(data){
		data = data.toString().trim().split(' ');
		var op = data.splice(0,1).toString().toLowerCase();
		switch(op){
			case 'help':
				console.log("Current commands: add help say kick op remove deop repl ops list exit");
				break;
			case 'say':
				broadcast('user-chat',"< Server >	"+data.join(' '));
				break;
			case 'kick':
				console.log("Attempting to kick "+data[0]);
				if(inArray(data[0],userlist())){
					for(var i in io.sockets.sockets){
						if(i&&io.sockets.sockets[i]!=undefined){
							io.sockets.sockets[i].get('nick',function(err,nick){
								if(!err&&nick==data[0]){
									console.log("Kicking "+nick);
									broadcast('user-chat',"* "+nick+" was kicked");
									io.sockets.sockets[i] = undefined;
									broadcast('user-list',userlist());
								}
							});
						}
					}
				}else{
					console.log("User does not exist");
				}
				break;
			case 'op':
				console.log("Attempting to op "+data[0]);
				if(inArray(data[0],userlist())){
					for(var i in io.sockets.sockets){
						if(i&&io.sockets.sockets[i]!=undefined){
							io.sockets.sockets[i].get('nick',function(err,nick){
								if(!err&&nick==data[0]){
									console.log("Opping "+nick);
									io.sockets.sockets[i].set('op','true');
									broadcast('user-list',userlist());
									broadcast('user-chat',"* "+nick+" was opped");
								}
							});
						}
					}
				}else{
					console.log("User does not exist");
				}
				break;
			case 'add':
				console.log("Attempting to add "+data[0]);
				if(inArray(data[0],userlist()) || inArray('@'+data[0],userlist())){
					for(var i in io.sockets.sockets){
						if(i&&io.sockets.sockets[i]!=undefined){
							io.sockets.sockets[i].get('nick',function(err,nick){
								if(!err&&nick==data[0]){
									console.log("Opping "+nick);
									io.sockets.sockets[i].set('op','true');
									broadcast('user-list',userlist());
									broadcast('user-chat',"* "+nick+" was opped");
									io.sockets.sockets[i].get('username',function(e,username){
										if(!e&&username){
											io.sockets.sockets[i].get('password',function(e,password){
												if(!e&&password){
													console.log("Adding "+nick);
													users.add(JSON.stringify({username:username,password:password}));
												}else{
													console.log("Can't add "+nick+" not enough info");
												}
											});
										}
									});
								}
							});
						}
					}
				}else{
					console.log("User does not exist");
				}
				break;
			case 'remove':
				console.log("Attempting to remove "+data[0]);
				if(inArray(data[0],userlist()) || inArray('@'+data[0],userlist())){
					for(var i in io.sockets.sockets){
						if(i&&io.sockets.sockets[i]!=undefined){
							io.sockets.sockets[i].get('nick',function(err,nick){
								if(!err&&nick==data[0]){
									console.log("Opping "+nick);
									io.sockets.sockets[i].set('op','false');
									broadcast('user-list',userlist());
									broadcast('user-chat',"* "+nick+" was deopped");
									io.sockets.sockets[i].get('username',function(e,username){
										if(!e&&username){
											io.sockets.sockets[i].get('password',function(e,password){
												if(!e&&password&&users.hasValue(JSON.stringify({username:username,password:password}))){
													console.log("Removing "+nick);
													users.remove(JSON.stringify({username:username,password:password}));
												}else{
													console.log("Can't remove "+nick+" not enough info");
												}
											});
										}
									});
								}
							});
						}
					}
				}else{
					console.log("User does not exist");
				}
				break;
			case 'deop':
				console.log("Attempting to deop "+data[0]);
				if(inArray("@"+data[0],userlist())){
					for(var i in io.sockets.sockets){
						if(i&&io.sockets.sockets[i]!=undefined){
							io.sockets.sockets[i].get('nick',function(err,nick){
								if(!err&&nick==data[0]){
									console.log("Deopping "+nick);
									io.sockets.sockets[i].set('op','false');
									broadcast('user-list',userlist());
									broadcast('user-chat',"* "+nick+" was deopped");
								}
							});
						}
					}
				}else{
					console.log("User does not exist");
				}
				break;
			case 'repl':
				require('repl').start();
				break;
			case 'ops':
				for(var i in io.sockets.sockets){
					if(i&&io.sockets.sockets[i]!=undefined){
						io.sockets.sockets[i].get('nick',function(err,nick){
							if(!err){
								io.sockets.sockets[i].get('op',function(err,op){
									if(op=='true'&&!err){
										console.log(nick+" is opped");
									}
								});
							}
						});
					}
				}
				break;
			case 'list':
				for(var i in userlist()){
					console.log(userlist()[i]);
				}
				break;
			case 'exit':
				process.exit();
				break;
		}
	}
	// Start Input Console
	stdin.on('data',inputConsole);
	stdin.resume();
	stdin.setEncoding('utf8');
}